unit filesform;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, ShellApi, Forms, Controls, Graphics,
  Dialogs, LCLIntf, LCLType, ComCtrls, StdCtrls, ExtCtrls, Buttons, Menus,
  formpanel, rccmd, rxtoolbar,  fpjson, LazUTF8,
  jsonparser;

type

  { TFilesPanel }

  TFilesPanel = class(TFormPanel)
  private
    FRootpath: string;
    FRAlias: string;
  public
    procedure ShowForm;override;
  published
    property  RAlias:string read FRAlias write FRAlias;
    property  RootPath:string read FRootpath write FRootPath;
  end;

  { TfrmFiles }

  TfrmFiles = class(TForm)
    ComboPath: TComboBox;
    ImageListFiles: TImageList;
    ImageListFilesToolbar: TImageList;
    ListFiles: TListView;
    MenuItem1: TMenuItem;
    MenuItem10: TMenuItem;
    MenuItem11: TMenuItem;
    MenuItem12: TMenuItem;
    MenuItem13: TMenuItem;
    MenuItem14: TMenuItem;
    MenuItem15: TMenuItem;
    MenuItem16: TMenuItem;
    MenuItem17: TMenuItem;
    MenuItem2: TMenuItem;
    MenuItem3: TMenuItem;
    MenuItem4: TMenuItem;
    MenuItem5: TMenuItem;
    MenuItem6: TMenuItem;
    MenuItem7: TMenuItem;
    MenuItem8: TMenuItem;
    MenuItem9: TMenuItem;
    OpenDialog1: TOpenDialog;
    Panel1: TPanel;
    PopActions: TPopupMenu;
    PopDisk: TPopupMenu;
    SelectDirectoryDialog1: TSelectDirectoryDialog;
    SpeedButton1: TSpeedButton;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton10: TToolButton;
    ToolButton11: TToolButton;
    ToolButton2: TToolButton;
    ToolButton3: TToolButton;
    ToolButton4: TToolButton;
    ToolButton5: TToolButton;
    ToolButton6: TToolButton;
    ToolButton7: TToolButton;
    ToolButton8: TToolButton;
    ToolButton9: TToolButton;
    procedure ComboPathKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
      );
    procedure ComboPathSelect(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure ListFilesDblClick(Sender: TObject);
    procedure ListFilesEdited(Sender: TObject; Item: TListItem;
      var AValue: string);
    procedure ListFilesEditing(Sender: TObject; Item: TListItem;
      var AllowEdit: Boolean);
    procedure MenuItem14Click(Sender: TObject);
    procedure MenuItem15Click(Sender: TObject);
    procedure MenuItem1Click(Sender: TObject);
    procedure MenuItem2Click(Sender: TObject);
    procedure MenuItem4Click(Sender: TObject);
    procedure MenuItem5Click(Sender: TObject);
    procedure MenuItem8Click(Sender: TObject);
    procedure SpeedButton1Click(Sender: TObject);
  private
    FCurrentPath: string;
    FRootpath: string;
    FrAlias: string;
    FValidPath: string;
  public
    function ListAndFill:boolean;
    procedure AddPath;
  published
    property  RAlias:string read FrAlias write FrAlias;
    property  RootPath:string read FRootpath write FRootPath;
    property  CurrentPath:string read FCurrentPath write FCurrentPath;
    property  ValidPath:string read FValidPath write FValidPath;

  end;

implementation

uses
  progressform;
{$R *.frm}

{ TfrmFiles }

procedure TfrmFiles.SpeedButton1Click(Sender: TObject);
begin
  if Self.Parent is TTabSheet then
  begin
    (Self.Parent as TTabSheet).Free;
  end;
end;

function TfrmFiles.ListAndFill:boolean;
var
  m:string;
  mStream2:TStringStream;
  mData : TJsonData;
  mArray:TJsonArray;
  i:integer;
  mItem:TJsonData;
begin
  //列出远端文件
  m:=RemoteLsjson(Self.RAlias,CurrentPath);
  //解析JSON
  mStream2:=TStringStream.Create(m,TEncoding.UTF8);
  mStream2.Seek(0,soBeginning);
  try
    mData := GetJSon(mStream2);
  Except
    mData := nil;
  end;
  //mTmp.Free;
  if mData<>nil then
  begin
    mArray := TJsonArray(mData);
    ListFiles.Items.BeginUpdate;
    ListFiles.Items.Clear;
    if CurrentPath<>'/' then
    begin
      with ListFiles.Items.Add do
      begin
        Caption := '..';
        SubItems.Add('(返回上级目录)');
        SubItems.Add('');
        SubItems.Add('');
        SubItems.Add('True');
        ImageIndex := 0;
      end;
    end;
    for i:=0 to mArray.Count-1 do
    begin
      mItem := mArray.Items[i];
      with ListFiles.Items.Add do
      begin
        Caption:=mItem.FindPath('Name').AsString;
        SubItems.Add(mItem.FindPath('ModTime').AsString);
        if Trim(mItem.FindPath('IsDir').AsString)='True' then
          SubItems.Add('目录')
        else
          SubItems.Add(mItem.FindPath('MimeType').AsString);
        if Trim(mItem.FindPath('IsDir').AsString)='True' then
          SubItems.Add('')
        else
          SubItems.Add(mItem.FindPath('Size').AsString);
        SubItems.Add(LowerCase(mItem.FindPath('IsDir').AsString));
        if Trim(mItem.FindPath('IsDir').AsString)='True' then
           ImageIndex := 1
        else
          ImageIndex := -1;
      end;
    end;
    ListFiles.Items.EndUpdate;
    Result:=True;
  end
  else
  begin
    MessageDlg('路径不存在，建议检查设置参数和网络情况。',mtError,[mbOK],0);
    Result:=False;
  end;
  mStream2.Free;
end;

procedure TfrmFiles.AddPath;
begin
  ComboPath.Text:=CurrentPath;
  if ComboPath.Items.IndexOf(CurrentPath)<0 then
    ComboPath.Items.Add(CurrentPath);
end;

procedure TfrmFiles.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  CloseAction:=caFree;
end;

procedure TfrmFiles.ComboPathKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then
  begin
    if Trim(ComboPath.Text)<>'' then
    begin
      CurrentPath := Trim(ComboPath.Text);
      if ListAndFill then
      begin
        AddPath;
        ValidPath := CurrentPath;
      end
      else
      begin
        CurrentPath := ValidPath;
        ComboPath.Text := ValidPath;
      end;
    end;
  end;
end;

procedure TfrmFiles.ComboPathSelect(Sender: TObject);
begin
  if ComboPath.ItemIndex>=0 then
  begin
    CurrentPath := Trim(ComboPath.Text);
    ValidPath := CurrentPath;
    ListAndFill;
  end;
end;

procedure TfrmFiles.FormShow(Sender: TObject);
begin
  if Trim(RootPath)='' then RootPath:='/';
  CurrentPath:=RootPath;
  ValidPath := CurrentPath;
  ComboPath.Text:=CurrentPath;
  if ComboPath.Items.IndexOf(CurrentPath)<0 then
    ComboPath.Items.Add(CurrentPath);
  //检查Alias是否存在
  if RemoteExists(Self.RAlias)=False then
  begin
    MessageDlg('远端存储不存在，或无法连接。',mtError,[mbOK],0);
    Exit;
  end;
  ListAndFill;
end;

procedure TfrmFiles.ListFilesDblClick(Sender: TObject);
var
  mDirName,mIsDir:string;
  mParentPath:string;
  mTmpFile:string;
  mSource,mTarget:string;
  mProgress:TfrmProgress;

begin
  //双击
  if Listfiles.Selected<>nil then
  begin
    mDirName := Trim(ListFiles.Selected.Caption);
    mIsDir   := Trim(ListFiles.Selected.SubItems.Strings[3]);
    if mDirName = '..' then
    begin
      //返回上级目录
      mParentPath := ParentDir(ValidPath);
      CurrentPath := mParentPath;
      if ListAndFill then
      begin
        ComboPath.Text := CurrentPath;
        ValidPath := CurrentPath;
      end;
    end
    else
    begin
      if Lowercase(mIsDir)='true' then
      begin
        //进入下级目录
        if ValidPath<>'/' then
          CurrentPath := ValidPath+'/'+mDirName
        else
          CurrentPath := '/'+mDirName;
        //ShowMessage(CurrentPath);
        if ListAndFill then
        begin
          ComboPath.Text := CurrentPath;
          ValidPath := CurrentPath;
          AddPath;
        end;
      end
      else
      begin
        mProgress:=TfrmProgress.Create(nil);
        mProgress.SetInfo('正在读取文件……');
        mProgress.Show;
        Application.ProcessMessages;
        //下载当前文件到临时文件
        mSource := Self.RAlias+':'+Self.ValidPath+'/'+Trim(ListFiles.Selected.Caption);
        mTarget := ExtractFilepath(Application.ExeName)+'temp\';
        DoCopy(mSource,mTarget);
        mTmpFile := mTarget+Trim(ListFiles.Selected.Caption);
        mProgress.Close;
        mProgress.Free;
        mProgress := nil;
        if FileExists(mTmpFile)=True then
        begin
          if OpenDocument(mTmpFile)=False then
          begin
            MessageDlg('没有找到默认的程序用以打开文件，请先下载到本地后再行处理。',mtWarning,[mbOK],0);
          end;
        end
        else
        begin
          MessageDlg('文件打开失败。',mtError,[mbOK],0);
        end;
      end;
    end;
  end;
end;

procedure TfrmFiles.ListFilesEdited(Sender: TObject; Item: TListItem;
  var AValue: string);
var
  mSource,mTarget:string;
begin
  //重命名
  if Trim(AValue)<>'' then
  begin
      mSource := Self.RAlias+':'+Self.ValidPath+'/'+Trim(Item.Caption);
      mTarget := Self.RAlias+':'+Self.ValidPath+'/'+AValue;
      if Trim(UpperCase(Item.SubItems.Strings[3]))='TRUE' then
      begin
        //重命名目录
        DoMove(mSource,mTarget);
      end
      else
      begin
        //重命名文件
        DoMoveTo(mSource,mTarget);
      end;
      ListFiles.ReadOnly:=True;
  end;
end;

procedure TfrmFiles.ListFilesEditing(Sender: TObject; Item: TListItem;
  var AllowEdit: Boolean);
begin

end;

procedure TfrmFiles.MenuItem14Click(Sender: TObject);
var
  i:integer;
  mCount:integer;
  mDirName:string;
  mSource:string;
begin
  //创建目录，先遍历当前列表查找新建文件夹的名字
  mCount := 0;
  for i:=0 to Listfiles.Items.Count-1 do
  begin
    if Pos('新建文件夹',ListFiles.Items.Item[i].Caption)=1 then
    begin
      mCount := Listfiles.Items.Count;//mCount+1;
    end;
  end;
  if mCount =0 then
    mDirName := '新建文件夹'
  else
    mDirName := '新建文件夹('+inttostr(mCount)+')';

  mSource := Self.RAlias+':'+Self.ValidPath+'/'+mDirName;

  DoMkdir(mSource);
  ListAndFill;

{  with ListFiles.Items.Add do
  begin
    Caption:=mDirName;
    SubItems.Add('');
    SubItems.Add('');
    SubItems.Add('');
    SubItems.Add('True');
    ImageIndex := 1;
  end;
  }
end;

procedure TfrmFiles.MenuItem15Click(Sender: TObject);
var
  i:integer;
  mMax,mCount:integer;
  mProgress:TfrmProgress;
  mSource:string;
begin
  //删除目录，先排除非目录
  for i:=0 to ListFiles.Items.Count-1 do
  begin
    if ListFiles.Items.Item[i].Selected then
    begin
      if Trim(UpperCase(ListFiles.Items.Item[i].SubItems.Strings[3]))<>'TRUE' then
      begin
        ListFiles.Items.Item[i].Selected:=False;
      end;
      if Trim(UpperCase(ListFiles.Items.Item[i].Caption))='..' then
      begin
        ListFiles.Items.Item[i].Selected:=False;
      end;
    end;
  end;
  if ListFiles.SelCount=0 then
  begin
    MessageDlg('请选择要删除的目录。',mtWarning,[mbOK],0);
    Exit;
  end;
  mCount:=0;
  mMax:=ListFiles.SelCount;
  mProgress:=TfrmProgress.Create(nil);
  mProgress.SetInfo('正在删除目录……'+inttostr(mCount)+'/'+inttostr(mMax));
  mProgress.Show;
  for i:=0 to ListFiles.Items.Count-1 do
  begin
    if ListFiles.Items.Item[i].Selected then
    begin
      mCount:=mCount+1;
      mProgress.SetInfo('正在删除目录……'+inttostr(mCount)+'/'+inttostr(mMax));
      if Trim(ListFiles.Items.Item[i].Caption)<>'..' then
      begin
        //删除
        mSource := Self.RAlias+':'+Self.ValidPath+'/'+Trim(ListFiles.Items.Item[i].Caption);
        DoPurge(mSource);
      end;
    end;
  end;
  //删除完成
  ListAndFill;
  mProgress.Close;
  mProgress.Free;
  mProgress := nil;
end;

procedure TfrmFiles.MenuItem1Click(Sender: TObject);
var
  i:integer;
  mFile:string;
  mProgress:TfrmProgress;
  mSource,mTarget:string;
begin
  //从本地上传
  if OpenDialog1.Execute then
  begin
    if OpenDialog1.Files.Count>0 then
    begin
      mProgress:=TfrmProgress.Create(nil);
      mProgress.SetInfo('正在上传文件……0/'+inttostr(OpenDialog1.Files.Count));
      mProgress.Show;
      for i:=0 to OpenDialog1.Files.Count-1 do
      begin
        mProgress.SetInfo('正在上传文件……'+inttostr(i+1)+'/'+inttostr(OpenDialog1.Files.Count));
        mFile := OpenDialog1.Files.Strings[i];
        //上传
        mSource := mFile;
        mTarget := Self.RAlias+':'+Self.ValidPath;
        DoCopy(mSource,mTarget);
      end;
      //复制完成，刷新目录
      ListAndFill;
      mProgress.Close;
      mProgress.Free;
      mProgress := nil;
    end;
  end;
end;

procedure TfrmFiles.MenuItem2Click(Sender: TObject);
var
  i,mCount,mMax:integer;
  mSource,mTarget:string;
  mProgress:TfrmProgress;
begin
  //排除目录
  for i:=0 to ListFiles.Items.Count-1 do
  begin
    if ListFiles.Items.Item[i].Selected then
    begin
      if Trim(UpperCase(ListFiles.Items.Item[i].SubItems.Strings[3]))='TRUE' then
        ListFiles.Items.Item[i].Selected := False;
    end;
  end;
  if ListFiles.SelCount=0 then
  begin
    MessageDlg('请选择要下载的文件（不含目录）。',mtWarning,[mbOK],0);
    Exit;
  end;
  mCount := 0;
  mMax := ListFiles.SelCount;
  if mMax > 0 then
  begin
    //从网盘下载到本地
    if SelectDirectoryDialog1.Execute then
    begin
      mProgress:=TfrmProgress.Create(nil);
      mProgress.SetInfo('正在下载文件……'+inttostr(mCount)+'/'+inttostr(mMax));
      mProgress.Show;
      for i:=0 to ListFiles.Items.Count-1 do
      begin
        if ListFiles.Items.Item[i].Selected then
        begin
          mCount:=mCount+1;
          mProgress.SetInfo('正在下载文件……'+inttostr(mCount)+'/'+inttostr(mMax));
          if Trim(ListFiles.Items.Item[i].Caption)<>'..' then
          begin
            //下载
            mSource := Self.RAlias+':'+Self.ValidPath+'/'+Trim(ListFiles.Items.Item[i].Caption);
            mTarget :=  SelectDirectoryDialog1.FileName;
            DoCopy(mSource,mTarget);
          end;
        end;
      end;
      mProgress.Close;
      mProgress.Free;
      mProgress := nil;
    end;
  end
  else
  begin
    MessageDlg('请选择要下载的文件。',mtWarning,[mbOK],0);
  end;
end;

procedure TfrmFiles.MenuItem4Click(Sender: TObject);
begin
  //重命名文件
  if ListFiles.SelCount=0 then
  begin
    MessageDlg('请选择要重命名的文件。',mtWarning,[mbOK],0);
    Exit;
  end;
  if ListFiles.SelCount>1 then
  begin
    MessageDlg('请选择要重命名的文件（只选一个）。',mtWarning,[mbOK],0);
    Exit;
  end;
  //重命名
  ListFiles.ReadOnly:=False;
  ListFiles.Selected.EditCaption;
end;

procedure TfrmFiles.MenuItem5Click(Sender: TObject);
begin

end;

procedure TfrmFiles.MenuItem8Click(Sender: TObject);
var
  i:integer;
  mMax,mCount:integer;
  mProgress:TfrmProgress;
  mSource:string;
begin
  //排除目录
  for i:=0 to ListFiles.Items.Count-1 do
  begin
    if ListFiles.Items.Item[i].Selected then
    begin
      if Trim(UpperCase(ListFiles.Items.Item[i].SubItems.Strings[3]))='TRUE' then
        ListFiles.Items.Item[i].Selected := False;
    end;
  end;
  //删除文件
  if ListFiles.SelCount=0 then
  begin
    MessageDlg('请选择要删除的文件（不含目录）',mtWarning,[mbOK],0);
    Exit;
  end;
  mMax := ListFiles.SelCount;
  mCount := 0;
  mProgress:=TfrmProgress.Create(nil);
  mProgress.SetInfo('正在删除文件……'+inttostr(mCount)+'/'+inttostr(mMax));
  mProgress.Show;
  for i:=0 to ListFiles.Items.Count-1 do
  begin
    if ListFiles.Items.Item[i].Selected then
    begin
      mCount:=mCount+1;
      mProgress.SetInfo('正在删除文件……'+inttostr(mCount)+'/'+inttostr(mMax));
      if Trim(ListFiles.Items.Item[i].Caption)<>'..' then
      begin
        //删除
        mSource := Self.RAlias+':'+Self.ValidPath+'/'+Trim(ListFiles.Items.Item[i].Caption);
        DoDeleteFiles(mSource);
      end;
    end;
  end;
  //删除完成
  ListAndFill;
  mProgress.Close;
  mProgress.Free;
  mProgress := nil;
end;

{ TFilesPanel }

procedure TFilesPanel.ShowForm;
var
  mform:TfrmFiles;
begin
  inherited ShowForm;
  mform:=TfrmFiles.Create(Self);
  mform.Parent:=Self;
  mform.Align:=alClient;
  mform.BorderStyle:=bsNone;
  mform.RAlias:=Self.RAlias;
  mForm.RootPath:=Self.RootPath;
  mform.Show;
end;

end.

